package abel.wlmr.model.type;

import abel.util.StdBcdNumber;
import abel.wlmr.model.WlmrUserData;
import abel.wlmr.model.WlmrException;
import io.netty.buffer.ByteBuf;

/**
 * 时间标签用于交换网络通道中，对采用同时建立多个通信服务的传输服务，进行辅助判决接收报文
 * 的时序和时效性。
 * 时间标签 Tp 由 6 字节组成，格式见表 B.8。
 * 表B.8 时 间 标 签 格 式
 * 数据名称 数据格式 单位 字节数
 * 启动帧的帧序号计数器 PFC BIN 1
 * 启动帧发送时标 见附录 C.16 秒分时日 4
 * 允许发送传输延时时间 BIN min 1
 * 间标签 Tp 由启动站产生，并通过报文传送给从动站，从动站据此判决收到的报文的时序和时效性，
 * 如判别有效，从动站发送响应帧，并在响应帧中将时间标签 Tp 返回启动站。
 * 启动帧的帧序号计数器 PFC： 见本附录 B.4.3.4.3.5 中的 b）。
 * 启动帧发送时标：记录启动帧发送的时间。
 * 允许发送传输延时时间：指启动帧从开始发送至从动站接收到报文之间启动站所允许的传输延时时
 * 间。
 * 从动站的时效性判断规则：
 * ——如从动站的当前时间与 Tp 中的启动帧发送时标之间的时间差大于 Tp 中的允许传输延时时间，
 * 从动站则舍弃该报文；
 * ——如时间差不大于 Tp 中的允许传输延时时间，则做出响应；
 * ——如 Tp 中的允许传输延时时间为“0”，则从动站不进行上述两项的判断。
 * 
 * @author Abel
 *
 */
public class TimeBody extends WlmrUserData {

    public static final short FIXED_LEN = 6;

    private short fpc;

    private StdBcdNumber sendTime;

    private short allowDelayMinutes;

    public TimeBody() {
        super(FIXED_LEN);
    }

    @Override
    public ByteBuf appendBuf(ByteBuf buf) {
        if (sendTime == null || sendTime.length() != 4) {
            throw new IllegalArgumentException("send time should be SMHD");
        }

        // may throw IAE
        sendTime.toMeterC16Joda();

        buf.writeByte(fpc);

        buf.writeBytes(sendTime.toBytes());

        buf.writeByte(allowDelayMinutes);

        return buf;
    }

    @Override
    public int parseBuf(ByteBuf buf) throws WlmrException {
        if (checkBuffer(buf) < 0) {
            return -1;
        }

        fpc = (short) (0xFF & buf.readByte());

        sendTime = new StdBcdNumber();
        sendTime.populateBytes(buf, 4);
        try {
            sendTime.toMeterC16Joda();
        } catch (IllegalArgumentException e) {
            throw new WlmrException(e);
        }

        allowDelayMinutes = (short) (0xFF & buf.readByte());

        return 6;
    }

    /* (non-Javadoc)
     * @see abel.wlmr.model.WlmrDataPart#getFinalLen()
     */
    @Override
    public short getFinalLen() {
        return FIXED_LEN;
    }

    /* (non-Javadoc)
     * @see abel.wlmr.model.WlmrDataPart#getMinLength()
     */
    @Override
    public int getMinLength() {
        return FIXED_LEN;
    }

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return String.format("{fpc:%s, sendTime:%s, allowDelayMinutes:%s}", fpc, sendTime, allowDelayMinutes);
    }

    /**
     * @return the fpc
     */
    public short getFpc() {
        return fpc;
    }

    /**
     * @param fpc
     *            the fpc to set
     */
    public void setFpc(short fpc) {
        if (fpc < 0 || fpc > 255) {
            throw new IllegalArgumentException("fpc should be [0,255]");
        }

        this.fpc = fpc;
    }

    /**
     * 启动帧发送时标 见附录 C.16 秒分时日 4
     * 
     * @return the sendTime
     */
    public StdBcdNumber getSendTime() {
        return sendTime;
    }

    /**
     * 启动帧发送时标 见附录 C.16 秒分时日 4
     * 
     * @param sendTime
     *            the sendTime to set
     */
    public TimeBody setSendTime(StdBcdNumber sendTime) {
        if (sendTime.length() != 4) {
            throw new IllegalArgumentException("send time should be SMHD");
        }

        this.sendTime = sendTime;

        return this;
    }

    /**
     * @return the allowDelayMinutes
     */
    public short getAllowDelayMinutes() {
        return allowDelayMinutes;
    }

    /**
     * @param allowDelayMinutes
     *            the allowDelayMinutes to set
     */
    public void setAllowDelayMinutes(short allowDelayMinutes) {
        if (allowDelayMinutes < 0 || allowDelayMinutes > 0xFF) {
            throw new IllegalArgumentException("allowDelayMinutes should be [0,255]");
        }

        this.allowDelayMinutes = allowDelayMinutes;
    }

}
